/**
 * <h3>Class description</h3> <h4>Date processing class</h4> <h4>Special Notes</h4>
 * 
 * @version 0.1
 * @author Vincent 2008-8-11
 * @support by
 * @version 0.2
 * @author songlin.li
 */
package com.dmagic.cms.common.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.StringTokenizer;

import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class DateUtil extends DateUtils {
    protected static transient final Log logger = LogFactory.getLog(DateUtil.class);

    private static final int[] dayArray = new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

    /**
     * sFormat = "yyyy-MM-dd";
     */

    public static final String FORMAT_1 = "yyyy-MM-dd";

    /**
     * sFormat = "yyyy-MM-dd HH:mm:ss";
     */

    public static final String FORMAT_2 = "yyyy-MM-dd HH:mm:ss";

    /**
     * sFormat = "yyyy-MM-dd EEE";
     */

    public static final String FORMAT_3 = "yyyy-MM-dd EEE";

    /**
     * sFormat = "dd/MM/yyyy";
     */
    public static final String FORMAT_4 = "dd/MM/yyyy";

    /**
     * sFormat = "dd/MM/yyyy HH:mm:ss";
     */
    public static final String FORMAT_5 = "dd/MM/yyyy HH:mm:ss";

    /**
     * sFormat = "dd MMM yyyy HH:mm:ss";
     */
    public static final String FORMAT_6 = "dd MMM yyyy HH:mm:ss";

    /**
     * sFormat = "dd MMM yyyy";
     */
    public static final String FORMAT_7 = "dd MMM yyyy";

    public final static int YEAR = 9;

    public final static int HOUR = 10;

    public final static int DAY = 11;

    public final static int MINUTE = 12;

    public final static int SECOND = 13;

    public final static int MILLISECOND = 14;

    /**
     * million Seconds Of Day
     */
    public static long millionSecondsOfDay = 86400000;

    /**
     * @description : convert java.util.Date to java.sql.Date
     * @param date -java.util.Date
     * @return
     */
    public static java.sql.Date convertUtilDateToSQLDate(java.util.Date date) {
        if (date == null)
            return null;
        Calendar cl = Calendar.getInstance();

        cl.setTime(date);
        java.sql.Date jd = new java.sql.Date(cl.getTimeInMillis());
        return jd;
    }

    /**
     * @description :convert java.sql.Date to java.util.Date
     * @param date -java.sql.Date
     * @return
     */
    public static java.util.Date convertSQLDateToUtilDate(java.sql.Date date) {
        if (date == null)
            return null;
        Calendar cl = Calendar.getInstance();

        cl.setTime(date);
        java.util.Date jd = new java.util.Date(cl.getTimeInMillis());
        return jd;
    }

    /**
     * @description : convert java.sql.Timestamp to java.util.Date
     * @param timestamp -java.sql.Timestamp
     * @return
     */
    public static java.util.Date convertSQLTimestampToUtilDate(java.sql.Timestamp timestamp) {
        long milliseconds = timestamp.getTime() + (timestamp.getNanos() / 1000000);
        return new java.util.Date(milliseconds);
    }

    /**
     * @description : Support Date Format:YYYY-MM-DD, YYYY:M:D, YYYY/M/DD
     * @param date
     * @return
     * @author songlin.li
     */
    @Deprecated
    public static Date stringToDate(String date) {
        if (date == null || "".equalsIgnoreCase(date))
            return null;

        Calendar cd = Calendar.getInstance();
        StringTokenizer token = new StringTokenizer(date, "-/ :.");
        if (token.hasMoreTokens()) {
            cd.set(Calendar.YEAR, Integer.parseInt(token.nextToken()));
        } else {
            cd.set(Calendar.YEAR, 1970);
        }
        if (token.hasMoreTokens()) {
            cd.set(Calendar.MONTH, Integer.parseInt(token.nextToken()) - 1);
        } else {
            cd.set(Calendar.MONTH, 0);
        }
        if (token.hasMoreTokens()) {
            cd.set(Calendar.DAY_OF_MONTH, Integer.parseInt(token.nextToken()));
        } else {
            cd.set(Calendar.DAY_OF_MONTH, 1);
        }
        if (token.hasMoreTokens()) {
            cd.set(Calendar.HOUR_OF_DAY, Integer.parseInt(token.nextToken()));
        } else {
            cd.set(Calendar.HOUR_OF_DAY, 0);
        }
        if (token.hasMoreTokens()) {
            cd.set(Calendar.MINUTE, Integer.parseInt(token.nextToken()));
        } else {
            cd.set(Calendar.MINUTE, 0);
        }
        if (token.hasMoreTokens()) {
            cd.set(Calendar.SECOND, Integer.parseInt(token.nextToken()));
        } else {
            cd.set(Calendar.SECOND, 0);
        }
        if (token.hasMoreTokens()) {
            cd.set(Calendar.MILLISECOND, Integer.parseInt(token.nextToken()));
        } else {
            cd.set(Calendar.MILLISECOND, 0);
        }

        return cd.getTime();
    }

    /**
     * @description :get First Date Of Current Month
     * @return
     */
    public static Date getFirstDateOfCurrentMonth() {
        Calendar cl = Calendar.getInstance();
        cl.set(Calendar.DAY_OF_MONTH, 1);
        return cl.getTime();
    }

    /**
     * @description : get First Date Of Month
     * @param date
     * @return
     */
    public static Date getFirstDateOfMonth(String date) {
        Calendar cl = Calendar.getInstance();
        cl.setTime(stringToDate(date));
        cl.set(Calendar.DAY_OF_MONTH, 1);
        return cl.getTime();
    }

    /**
     * @description : get Last Date Of Month
     * @param date
     * @return
     */
    public static Date getLastDateOfMonth(String date) {
        Calendar cl = Calendar.getInstance();
        cl.setTime(stringToDate(date));
        int year = cl.get(Calendar.YEAR);
        int month = cl.get(Calendar.MONTH) + 1;
        int day = 0;
        if (month < 1 || month > 12)
            return null;

        if (month == 2) {
            if (isLeapYear(year)) {
                day = 29;
            } else {
                day = dayArray[month - 1];
            }
        } else {
            day = dayArray[month - 1];
        }

        cl.set(Calendar.DAY_OF_MONTH, day);

        return cl.getTime();
    }

    /**
     * @description :  is LeapYear
     * @param year
     * @return
     */
    public static boolean isLeapYear(int year) {

        if ((year % 400) == 0)
            return true;
        else if ((year % 4) == 0) {
            if ((year % 100) == 0)
                return false;
            else
                return true;
        } else
            return false;
    }

    /**
     * @description : Access to current time before time
     * @author Leo.Li 2007-07-03
     * @param type DateUtil.DAY,DateUtil.HOUR...
     * @param value
     * @return
     */
    public static Date getDateTimeBeforeNow(int type, int value) {
        Calendar cd = Calendar.getInstance();
        long nextTime = cd.getTimeInMillis();

        switch (type) {
            case DAY:
                nextTime = nextTime - 24 * 60 * 60 * 1000 * value;
                break;
            case HOUR:
                nextTime = nextTime - 60 * 60 * 1000 * value;
                break;
            case MINUTE:
                nextTime = nextTime - 60 * 1000 * value;
                break;
            case SECOND:
                nextTime = nextTime - 1000 * value;
                break;
            default:
                break;
        }
        return new Date(nextTime);

    }

    /**
     * @description : Access to current time after time
     * @param date
     * @param type
     * @param value
     * @return
     */
    public static Date getDateTimeAfter(Date date, int type, long value) {
        // Calendar cd = Calendar.getInstance();
        long nextTime = date.getTime();

        switch (type) {
            case DAY:
                nextTime = nextTime + 24 * 60 * 60 * 1000 * value;
                break;
            case HOUR:
                nextTime = nextTime + 60 * 60 * 1000 * value;
                break;
            case MINUTE:
                nextTime = nextTime + 60 * 1000 * value;
                break;
            case SECOND:
                nextTime = nextTime + 1000 * value;
                break;
            case MILLISECOND:
                nextTime = nextTime + value;
                break;
            default:
                break;
        }
        return new Date(nextTime);

    }

    /*
     * Get the Next Date Write by Jeffy pan 2004-10-21 Date Format:YYYY-MM-DD
     * YYYY:M:D YYYY/M/DD
     */
    @Deprecated
    public static Date getNextDate(String date) {

        Calendar cd = Calendar.getInstance();
        StringTokenizer token = new StringTokenizer(date, "-/ :.");
        if (token.hasMoreTokens()) {
            cd.set(Calendar.YEAR, Integer.parseInt(token.nextToken()));
        } else {
            cd.set(Calendar.YEAR, 1970);
        }
        if (token.hasMoreTokens()) {
            cd.set(Calendar.MONTH, Integer.parseInt(token.nextToken()) - 1);
        } else {
            cd.set(Calendar.MONTH, 0);
        }
        if (token.hasMoreTokens()) {
            cd.set(Calendar.DAY_OF_MONTH, Integer.parseInt(token.nextToken()));
        } else {
            cd.set(Calendar.DAY_OF_MONTH, 1);
        }
        if (token.hasMoreTokens()) {
            cd.set(Calendar.HOUR_OF_DAY, Integer.parseInt(token.nextToken()));
        } else {
            cd.set(Calendar.HOUR_OF_DAY, 0);
        }
        if (token.hasMoreTokens()) {
            cd.set(Calendar.MINUTE, Integer.parseInt(token.nextToken()));
        } else {
            cd.set(Calendar.MINUTE, 0);
        }
        if (token.hasMoreTokens()) {
            cd.set(Calendar.SECOND, Integer.parseInt(token.nextToken()));
        } else {
            cd.set(Calendar.SECOND, 0);
        }
        if (token.hasMoreTokens()) {
            cd.set(Calendar.MILLISECOND, Integer.parseInt(token.nextToken()));
        } else {
            cd.set(Calendar.MILLISECOND, 0);
        }

        long nextTime = cd.getTimeInMillis() + 24 * 60 * 60 * 1000;
        // SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        return new Date(nextTime);
    }

    /**
     * @description :isToday
     * @param date
     * @return
     */
    public static boolean isToday(Date date) {

        Calendar today = Calendar.getInstance();
        today.setTime(new Date());
        Calendar day = Calendar.getInstance();
        day.setTime(date);

        if (today.get(Calendar.YEAR) == day.get(Calendar.YEAR) && today.get(Calendar.MONTH) == day.get(Calendar.MONTH)
                && today.get(Calendar.DAY_OF_MONTH) == day.get(Calendar.DAY_OF_MONTH))
            return true;
        else
            return false;
    }

    /**
     * @description : default format is yyyy-MM-dd
     * 
     * @author songlin.li
     * @param sDate
     * @param format FORMAT_1 TO FORMAT_7
     * @return
     */
    public static Date stringToDate(String sDate, String format) {
        return parse(sDate, StringUtil.isBlank(format) ? FORMAT_1 : format);
    }

    /**
     * @description : default format is yyyy-MM-dd
     * 
     * @author songlin.li
     * @param dDate
     * @param nFormat FORMAT_1 TO FORMAT_7
     * @return
     */
    public static String dateToString(Date dDate, String format) {
        return format(dDate, StringUtil.isBlank(format) ? FORMAT_1 : format);
    }

    /**
     * @description : default format yyyy-MM-dd HH:mm:ss
     * 
     * @author songlin.li
     * @param date
     * @return
     */
    public static String defaultFormatTimeStamp(Date date) {
        return dateToString(date, null);
    }

    /**
     * @description : default format yyyy-MM-dd HH:mm:ss
     * 
     * @author songlin.li
     * @param date
     * @return
     * @throws Exception
     */
    public static Date defaultParseTimeStamp(String date) throws Exception {
        return stringToDate(date, null);
    }

    /**
     * @description : Get the number of days between two date
     * 
     * @author Vincent
     * @param date1
     * @param date2
     * @return
     */
    public static int getDay(Date date1, Date date2) {
        Long d2 = date2.getTime();
        Long d1 = date1.getTime();
        return (int) ((d2 - d1) / millionSecondsOfDay);
    }

    /**
     * @description : According to the date it's Thursday
     * 
     * @author Vincent
     * @param date Date
     * @return int return 1-7
     */
    public static int getWeekOfDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return (calendar.get(Calendar.DAY_OF_WEEK) - 1) == 0 ? 7 : calendar.get(Calendar.DAY_OF_WEEK) - 1;
    }

    /**
     * @description : formater "yyyy-MM-dd HH:mm:ss","dd/MM/yyyy"....
     * 
     * @author songlin.li
     * @param date
     * @param formater
     * @return
     */
    public static Date parse(String date, String formater) {
        if (StringUtil.isBlank(date))
            return null;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(formater, Locale.ENGLISH);
            sdf.setLenient(false);
            return sdf.parse(date);
        } catch (ParseException e) {
            logger.error(e.getMessage());
            return null;
        }
    }

    /**
     * @description : format "yyyy-MM-dd HH:mm:ss","dd/MM/yyyy"....
     * 
     * @param date
     * @param formater
     * @return
     * @author songlin.li
     */
    public static String format(Date date, String formater) {
        if (date == null)
            return null;
        SimpleDateFormat formatter = new SimpleDateFormat(formater, Locale.ENGLISH);
        return formatter.format(date).trim();
    }

    public static void main(String[] args) {

    }
}
